package com.ilm.sandwich.tools;
import android.content.Context;
import android.content.SharedPreferences;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.GpsStatus.Listener;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.ilm.sandwich.BackgroundService;
import com.ilm.sandwich.BuildConfig;
import com.ilm.sandwich.GoogleMap;
import com.ilm.sandwich.sensors.Core;
import java.util.Iterator;
/**
* This class is used to determine the start location
* and to get location for the autocorrect feature
*
* @author Christian Henke
* www.smartnavi-app.com
*/
public class Locationer implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener, com.google.android.gms.location.LocationListener {
public static double startLat;
public static double startLon;
public static double errorGPS;
public static float lastErrorGPS = 9999999999.0f;
private onLocationUpdateListener locationListener;
private int satellitesInRange = 0;
private Handler mHandler = new Handler();
private int allowedErrorGps = 10;
private boolean autoCorrectSuccess = true;
private int additionalSecondsAutocorrect = 0;
private boolean giveGpsMoreTime = true;
private GoogleApiClient mGoogleApiClient;
private LocationRequest highRequest;
private long lastLocationTime = 0L;
private LocationManager mLocationManager;
private Context mContext;
private Listener mGpsStatusListener = new Listener() {
@Override
public void onGpsStatusChanged(int event) {
switch (event) {
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
updateSats();
break;
}
}
};
private Runnable deaktivateTask = new Runnable() {
public void run() {
deactivateLocationer();
}
};
private LocationListener gpsAutocorrectLocationListener = new LocationListener() {
public void onLocationChanged(Location location) {
if (location.getLatitude() != 0) {
location.getProvider();
startLat = location.getLatitude();
startLon = location.getLongitude();
errorGPS = location.getAccuracy();
if (errorGPS <= allowedErrorGps) {
if (BuildConfig.debug)
Log.i("Location-Status", "Autocorrect GPS: " +
location.getProvider() + " "
+ location.getAccuracy());
locationListener.onLocationUpdate(8);
allowedErrorGps = 10;
autoCorrectSuccess = true;
additionalSecondsAutocorrect = 0;
} else {
if (giveGpsMoreTime) {
//Positions are coming in, but they are to inaccurate
//so give some extra time
mHandler.removeCallbacks(autoStopTask);
mHandler.postDelayed(autoStopTask,
10000 + additionalSecondsAutocorrect * 1000);
giveGpsMoreTime = false;
}
if (BuildConfig.debug)
Log.i("Location-Status", "DISCARDED: Autocorrect GPS: " + location.getProvider() + " " + location.getAccuracy());
}
}
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
public void onProviderEnabled(String provider) {
}
public void onProviderDisabled(String provider) {
}
};
private Runnable autoStopTask = new Runnable() {
public void run() {
stopAutocorrect();
}
};
private Runnable satelitesInRangeTest = new Runnable() {
public void run() {
if (satellitesInRange < 5) {
stopAutocorrect();
if (BuildConfig.debug)
Log.i("Location-Status", "Not enough satelites in range: " + satellitesInRange);
}
}
};
// LocationClient
// **************
public Locationer(Context context) {
super();
if (context instanceof onLocationUpdateListener) {
locationListener = (onLocationUpdateListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
mContext = context;
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
public void deactivateLocationer() {
//ProgressBar must be made invisible (GONE)
locationListener.onLocationUpdate(12);
try {
if (mGoogleApiClient.isConnected()) {
try {
mLocationManager.removeUpdates(this);
} catch (SecurityException e) {
e.printStackTrace();
}
mGoogleApiClient.disconnect();
}
} catch (Exception e) {
//nothing
}
try {
mLocationManager.removeUpdates(this);
} catch (SecurityException e) {
e.printStackTrace();
}
}
public void startLocationUpdates() {
GoogleApiAvailability api = GoogleApiAvailability.getInstance();
int status = api.isGooglePlayServicesAvailable(mContext);
if (status != ConnectionResult.SUCCESS) {
try {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10, 0, this);
if (mLocationManager.getAllProviders().contains("network")) {
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10, 0, this);
}
mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 10, 0, this);
} catch (SecurityException e) {
e.printStackTrace();
}
} else {
// get first position
mGoogleApiClient.connect();
}
}
private void updateSats() {
try {
final GpsStatus gs = this.mLocationManager.getGpsStatus(null);
int i = 0;
final Iterator<GpsSatellite> it = gs.getSatellites().iterator();
while (it.hasNext()) {
it.next();
i += 1;
}
if (BuildConfig.debug) {
Log.i("Location-Status", "Satelites in range: " + i);
}
satellitesInRange = i;
} catch (SecurityException e) {
e.printStackTrace();
}
}
@Override
public void onConnectionFailed(ConnectionResult arg0) {
if (BuildConfig.debug) {
Log.i("Location-Status", "Connection FAILED" + arg0.getErrorCode());
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onConnected(Bundle arg0) {
if (BuildConfig.debug) {
Log.i("Location-Status", "onConnected");
}
try {
Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (lastLocation != null) {
double startLat = lastLocation.getLatitude();
double startLon = lastLocation.getLongitude();
lastErrorGPS = lastLocation.getAccuracy();
double altitude = lastLocation.getAltitude();
lastLocationTime = lastLocation.getTime();
if (BuildConfig.debug) {
Log.i("Location-Status", "Last-Location: Error=" + lastErrorGPS + " Time:" + lastLocationTime);
}
double middleLat = startLat * 0.01745329252;
double distanceLongitude = 111.3D * Math.cos(middleLat);
Core.initialize(startLat, startLon, distanceLongitude, altitude, lastErrorGPS);
}
highRequest = LocationRequest.create();
highRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
highRequest.setInterval(1000); // Update location every second
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, highRequest, this);
locationListener.onLocationUpdate(0);
// remove location updates after 40s automatically
mHandler.postDelayed(deaktivateTask, 40000);
} catch (SecurityException e) {
LocationManager locManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
boolean locationEnabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (locationEnabled == false) {
//no position has ever been requested or Location Services are deactivated, so tell the user to activate them
if(BuildConfig.debug){
Log.i("Location-Status", "Security Exception");
}
locationListener.onLocationUpdate(5);
} else {
// location services are activated but no location has ever been requested
// so, start with 0,0 and hope the best
double startLat = 0;
double startLon = 0;
lastErrorGPS = 1000000;
double altitude = 0;
lastLocationTime = System.currentTimeMillis() - 1000000;
double middleLat = startLat * 0.01745329252;
double distanceLongitude = 111.3 * Math.cos(middleLat);
Core.initialize(startLat, startLon, distanceLongitude, altitude, lastErrorGPS);
locationListener.onLocationUpdate(8);
// nach 40sek automatisch location updates removen
mHandler.postDelayed(deaktivateTask, 40000);
}
}
}
@Override
public void onConnectionSuspended(int i) {
if (BuildConfig.debug) {
Log.i("Location-Status", "Connection suspended!");
}
}
@Override
public void onLocationChanged(Location location) {
if (BuildConfig.debug) {
Log.i("Location-Status", "onLocationChanged Acc:" + location.getAccuracy());
}
long differenceTime = location.getTime() - lastLocationTime;
double differenceError = lastErrorGPS - location.getAccuracy();
if (differenceTime > 30000 || differenceError > 7) {
double startLat = location.getLatitude();
double startLon = location.getLongitude();
lastErrorGPS = location.getAccuracy();
double altitude = location.getAltitude();
lastLocationTime = location.getTime();
double middleLat = startLat * 0.01745329252;
double distanceLongitude = 111.3D * Math.cos(middleLat);
Core.initialize(startLat, startLon, distanceLongitude, altitude, lastErrorGPS);
locationListener.onLocationUpdate(14);
if (location.getAccuracy() < 16) {
try {
deactivateLocationer();
} catch (Exception e) {
if (BuildConfig.debug)
e.printStackTrace();
}
}
lastLocationTime = location.getTime();
lastErrorGPS = location.getAccuracy();
} else {
//for debug purposes
}
}
// ******************************************************************
// ******************** AutoCorrection with GPS ******************
// ******************************************************************
@Override
public void onProviderDisabled(String provider) {
SharedPreferences settings = mContext.getSharedPreferences(mContext.getPackageName() + "_preferences", Context.MODE_PRIVATE);
if (BuildConfig.debug) {
Log.i("Location-Status", "onProviderDisabled");
}
if (settings.getBoolean("gpsDialogShown", false) == false) {
new writeSettings("gpsDialogShown", true).execute();
locationListener.onLocationUpdate(5);
}
}
public void starteAutocorrect() {
if (autoCorrectSuccess) {
autoCorrectSuccess = false;
} else if (additionalSecondsAutocorrect <= 30) {
additionalSecondsAutocorrect = additionalSecondsAutocorrect + 7;
allowedErrorGps = allowedErrorGps + 8;
if (BuildConfig.debug)
Log.i("Location-Status", "Time for request:" + additionalSecondsAutocorrect + " and allowed Error: " + allowedErrorGps);
}
try {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
100, 0, gpsAutocorrectLocationListener);
mHandler.postDelayed(autoStopTask,
10000 + additionalSecondsAutocorrect * 1000);
mHandler.postDelayed(satelitesInRangeTest, 10000);
mLocationManager.addGpsStatusListener(mGpsStatusListener);
giveGpsMoreTime = true;
} catch (SecurityException e) {
e.printStackTrace();
}
}
public void stopAutocorrect() {
try {
mLocationManager.removeGpsStatusListener(mGpsStatusListener);
mLocationManager.removeUpdates(gpsAutocorrectLocationListener);
mHandler.removeCallbacks(autoStopTask);
mHandler.removeCallbacks(satelitesInRangeTest);
if (BuildConfig.debug)
Log.i("Location-Status", "shutdown Autocorrect");
if (GoogleMap.backgroundServiceShallBeOnAgain == true) {
Config.backgroundServiceActive = true;
BackgroundService.reactivateFakeProvider();
}
} catch (SecurityException e) {
e.printStackTrace();
}
}
@Override
public void onProviderEnabled(String provider) {
}
public interface onLocationUpdateListener {
void onLocationUpdate(int event);
}
private class writeSettings extends AsyncTask<Void, Void, Void> {
private String key;
private int dataType;
private boolean setting1;
private writeSettings(String key, boolean setting1) {
this.key = key;
this.setting1 = setting1;
dataType = 0;
}
@Override
protected Void doInBackground(Void... params) {
SharedPreferences settings = mContext.getSharedPreferences(mContext.getPackageName() + "_preferences", Context.MODE_PRIVATE);
if (dataType == 0) {
settings.edit().putBoolean(key, setting1).commit();
}
return null;
}
}
}